package com.yhsoft.flim.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yhsoft.benefitcard.entity.BatchGoods;
import com.yhsoft.benefitcard.entity.CardsBatch2;
import com.yhsoft.benefitcard.entity.CardsInfo;
import com.yhsoft.benefitcard.mapper.CardsBatch2Mapper;
import com.yhsoft.benefitcard.service.IBatchGoodsService;
import com.yhsoft.benefitcard.service.ICardsInfoService;
import com.yhsoft.buyer.entity.BuyerOrder;
import com.yhsoft.buyer.service.IBuyerOrderService;
import com.yhsoft.buyer.service.IBuyerPaymentService;
import com.yhsoft.buyer.service.IBuyerUserService;
import com.yhsoft.common.service.FuSiLingFlimApiService;
import com.yhsoft.common.service.TokenService;
import com.yhsoft.common.utils.IDGenerator;
import com.yhsoft.common.vo.Result;
import com.yhsoft.flim.controller.po.FlimAddPricePo;
import com.yhsoft.flim.controller.po.JsonData;
import com.yhsoft.flim.controller.po.JsonQueryData;
import com.yhsoft.flim.controller.request.*;
import com.yhsoft.flim.controller.response.*;
import com.yhsoft.flim.entity.MoviePlans;
import com.yhsoft.flim.entity.MovieSeat;
import com.yhsoft.flim.service.IFlimService;
import com.yhsoft.flim.service.IMoviePlansService;
import com.yhsoft.goods.entity.CompanyGoods;
import com.yhsoft.goods.mapper.CompanyGoodsMapper;
import com.yhsoft.goods.service.ICompanyGoodsService;
import com.yhsoft.goods.service.IGoodsInfoService;
import com.yhsoft.wxprogram.controller.request.FlkPayInVo;
import com.yhsoft.wxprogram.controller.response.BenefitCardOutVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author: yyyyyyyh
 * @create: 2023-12-10
 * @Version 1.0
 **/
@Service
@Slf4j
public class FlimServiceImpl implements IFlimService {

    @Resource
    private CompanyGoodsMapper companyGoodsMapper;

    @Resource
    private IMoviePlansService iMoviePlansService;

    @Resource
    private IBuyerUserService iBuyerUserService;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private IBuyerOrderService iBuyerOrderService;

    @Resource
    private IBuyerPaymentService iBuyerPaymentService;

    @Override
    public List<MovieSeat> getMovieSeat(GetMovieSeatInVo inVo) throws IOException {
        List<MovieSeat> movieSeatList = null;
        String msg = FuSiLingFlimApiService.movieSeat(inVo.getShowId());

        log.info(msg);

        JsonData movieSeatJson = JSON.parseObject(msg, JsonData.class);
        if (movieSeatJson.getData() == null || movieSeatJson.getData().size() == 0) {
            return null;
        }

        String data = movieSeatJson.getData().toString();

        // 解析
        movieSeatList = JSON.parseArray(data, MovieSeat.class);

        // 修改价格
        this.setAddPrice(movieSeatList);

        return movieSeatList;
    }

    @Override
    public MovieSeatLockOutVo movieSeatLock(MovieSeatLockInVo inVo) throws IOException {
        MovieSeatLockOutVo outVo = new MovieSeatLockOutVo();
        String phoneNum = iBuyerUserService.getUserPhoneNum();
        if (StringUtils.isEmpty(phoneNum)) {
            outVo.setSuccess(false);
            outVo.setMsg("获取手机号失败！请授权手机号！");
            return outVo;
        }

        String msg = FuSiLingFlimApiService.movieSeatLock(inVo, phoneNum);

        log.info(msg);

        // 解析
        outVo = JSON.parseObject(msg, MovieSeatLockOutVo.class);
        outVo.setPhoneNum(phoneNum);

        // 检查showTime
        MovieSeatLockOutVo finalOutVo = outVo;
        if (outVo.isSuccess()) {
            outVo.getApplyKey();
            String key = "FlimOriginalPrice:ApplyKey:" + outVo.getApplyKey();
            // 存入redis,60min失效
            redisTemplate.opsForValue().set(key, inVo.getTotalMoney(), 60, TimeUnit.MINUTES);
        }
        // 后期若卡顿，可考虑另开线程单独检查放映时间
//        Thread thread2 = new Thread(new Runnable() {
//            @Override
//            public void run() {
//                try {
//                    checkShowTime(inVo, finalOutVo);
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }
//        });
//        thread2.start();
        checkShowTime(inVo, finalOutVo);

        return outVo;
    }

    private void checkShowTime(MovieSeatLockInVo inVo, MovieSeatLockOutVo outVo) throws IOException {
        if (outVo.isSuccess() && outVo.getShowTime() != null) {
            String showId = inVo.getShowId();
            GetMoviePlansInVo moviePlansInVo = new GetMoviePlansInVo(inVo.getCinemaId(), inVo.getMovieId());

            MoviePlans moviePlans = iMoviePlansService.getMoviePlan(moviePlansInVo, showId);

            if (moviePlans != null && !outVo.getShowTime().contains(moviePlans.getShowStartTime())) {
                iMoviePlansService.setMoviePlans(moviePlansInVo);
            }
        }
    }

    @Override
    public MovieSeatUnlockOutVo movieSeatUnlock(MovieSeatUnlockInVo inVo) throws IOException {
        MovieSeatUnlockOutVo outVo;
        String msg = FuSiLingFlimApiService.movieSeatUnLock(inVo.getApplyKey());

        log.info(msg);

        // 解析
        outVo = JSON.parseObject(msg, MovieSeatUnlockOutVo.class);

        return outVo;
    }

    @Override
    public FlimPayOutVo pay(FlimPayInVo inVo) throws IOException {
        FlimPayOutVo outVo = new FlimPayOutVo();
        String result = iBuyerOrderService.flkpay(new FlkPayInVo(inVo.getOrderId(), inVo.getPayPrice(),
                inVo.getCardIds()));
        if (!result.equals("success")) {
            outVo.setSuccess(false);
            outVo.setMsg(result);
            return outVo;
        }

        String orderId = inVo.getOrderId();

        String key = "order:ApplyKey:" + orderId;
        Object a = redisTemplate.opsForValue().get(key);
        if (a == null) {
            outVo.setSuccess(false);
            outVo.setMsg("该订单已超时！");
            return outVo;
        }

        String applyKey = redisTemplate.opsForValue().get(key).toString();
        key = "order:IsChangeSeats:" + orderId;
        String isChangeSeats = redisTemplate.opsForValue().get(key).toString();

        String msg = FuSiLingFlimApiService.payConfirm(orderId, applyKey, isChangeSeats);

        log.info(msg);

        // 解析
        outVo = JSON.parseObject(msg, FlimPayOutVo.class);

        if (outVo.isSuccess()) {
            outVo.setOrderId(orderId);
            BuyerOrder buyerOrder = iBuyerOrderService.getBaseMapper().selectById(orderId);
            buyerOrder.setFlimTicketInfo(outVo.getMsg());
            iBuyerOrderService.updateById(buyerOrder);
        }
        return outVo;
    }

    @Override
    public FlimPayOutVo payFlim(String orderId) throws IOException {
        FlimPayOutVo outVo = new FlimPayOutVo();
        // 1. 校验订单状态
        BuyerOrder buyerOrder = iBuyerOrderService.getBaseMapper().selectById(orderId);
        if (buyerOrder == null) {
            outVo.setSuccess(false);
            outVo.setMsg("找不到订单信息！");
            return outVo;
        }
        if (buyerOrder.getOrderStatus() != 2) {
            outVo.setSuccess(false);
            outVo.setMsg("该订单未完成支付！");
            return outVo;
        }

        String key = "order:ApplyKey:" + orderId;
        Object a = redisTemplate.opsForValue().get(key);
        if (a == null) {
            outVo.setSuccess(false);
            outVo.setMsg("该订单已超时！");
            return outVo;
        }
        String applyKey = redisTemplate.opsForValue().get(key).toString();
        key = "order:IsChangeSeats:" + orderId;
        String isChangeSeats = redisTemplate.opsForValue().get(key).toString();

        String msg = FuSiLingFlimApiService.payConfirm(orderId, applyKey, isChangeSeats);

        log.info(msg);

        // 解析
        outVo = JSON.parseObject(msg, FlimPayOutVo.class);

        if (outVo.isSuccess()) {
            outVo.setOrderId(orderId);
            buyerOrder.setFlimTicketInfo(outVo.getMsg());
            iBuyerOrderService.updateById(buyerOrder);
        }
        return outVo;
    }

    @Override
    public QueryOutVo query(String orderId) throws IOException {
        QueryOutVo outVo;
        String msg = FuSiLingFlimApiService.query(orderId);
        log.info(msg);

        // 解析
        JsonQueryData json = JSON.parseObject(msg, JsonQueryData.class);
        if (json.getData() == null) {
            return null;
        }

        outVo = json.getData();
        if (outVo.getStatus().equals("success")) {
            BuyerOrder buyerOrder = iBuyerOrderService.getBaseMapper().selectById(orderId);
            buyerOrder.setFlimTicketInfo(outVo.getTicketCode());
            buyerOrder.setOrderStatus(0);
            buyerOrder.setEndTime(LocalDateTime.now());
            iBuyerOrderService.updateById(buyerOrder);
        } else if (outVo.getStatus().equals("refund") || outVo.getStatus().equals("fail")) {
            // TODO: 如果是退款或者出票失败，走退款逻辑
            BuyerOrder buyerOrder = iBuyerOrderService.getBaseMapper().selectById(orderId);
            if (buyerOrder.getOrderStatus() == 2) {
                // 1. 福利卡支付 ==>> 积分退款接口
                if (buyerOrder.getPayMethod().equals("1")) {
                    iBuyerOrderService.refund(buyerOrder);
                }
                // 2. 现金支付  ==>> 微信退款接口 和 退款状态查询接口
                if (buyerOrder.getPayMethod().equals("2")) {
                    iBuyerPaymentService.orderRefund(buyerOrder.getOrderId()).getData();
                    Map<String, Object> resultMap = iBuyerPaymentService.queryRefundStatus(buyerOrder.getOrderId());
                    iBuyerOrderService.refundSuccess(resultMap);
                }
                // 3. 混合支付  ==>> 积分退款接口 微信退款接口 和 退款状态查询接口
                if (buyerOrder.getPayMethod().equals("3")) {
                    iBuyerOrderService.refund(buyerOrder);
                    iBuyerPaymentService.orderRefund(buyerOrder.getOrderId());
                    Map<String, Object> resultMap = iBuyerPaymentService.queryRefundStatus(buyerOrder.getOrderId());
                    iBuyerOrderService.refundSuccess(resultMap);
                }
            }
        }
        return outVo;
    }

    @Override
    public SubmitOutVo submit(FlimSubmitInVo inVo) {
        SubmitOutVo outVo = new SubmitOutVo();

        String orderId = IDGenerator.generate20("Order");
        BuyerOrder order = new BuyerOrder();
        order.setOrderId(orderId);
        order.setFlimInfo(inVo.getFlimInfo());
        order.setPoster(inVo.getPoster());
        order.setDistributorId(TokenService.getUserBytoken().getCompanyId());
        order.setUserId(TokenService.getUserBytoken().getId());
        // 记录价格
        order.setTotalPrice(inVo.getTotalMoney());

        String key = "FlimOriginalPrice:ApplyKey:" + inVo.getApplyKey();
        // 读取redis
        String originalPrice = redisTemplate.opsForValue().get(key).toString();
        if (org.springframework.util.StringUtils.hasLength(originalPrice)) {
            // 记录原价
            BigDecimal originalPriceBigd =
                    BigDecimal.valueOf(Long.parseLong(originalPrice)).divide(BigDecimal.valueOf(100));
            order.setTotalOriginalPrice(originalPriceBigd);
            // 记录渠道商进货价
            // 获取服务费
            LambdaQueryWrapper<CompanyGoods> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(CompanyGoods::getCompanyId, TokenService.getUserBytoken().getCompanyId());
            wrapper.eq(CompanyGoods::getGoodsId, 0);
            CompanyGoods companyGoods = companyGoodsMapper.selectOne(wrapper);
            if (companyGoods != null) {
                BigDecimal charge = companyGoods.getCustomCharge() != null ?
                        new BigDecimal(companyGoods.getCustomCharge()).divide(new BigDecimal(100)) : BigDecimal.ZERO;
                BigDecimal totalSalerPrice = originalPriceBigd.multiply(BigDecimal.ONE.add(charge));
                order.setTotalSalerPrice(totalSalerPrice);
            }
        }

        order.setOrderStatus(1);
        order.setOrderType("DY");
        int i = iBuyerOrderService.getBaseMapper().insert(order);
        if (i > 0) {
            outVo.setOrderId(orderId);
            outVo.setPrice(inVo.getTotalMoney());
            key = "order:ApplyKey:" + orderId;
            log.info(">>>>>>设置缓存：key：order:ApplyKey:" + key);
            log.info(">>>>>>设置缓存：value:" + inVo.getApplyKey());
            // 存入redis,15min失效
            redisTemplate.opsForValue().set(key, inVo.getApplyKey(), 60, TimeUnit.MINUTES);
            key = "order:IsChangeSeats:" + orderId;
            log.info(">>>>>>设置缓存：key：order:IsChangeSeats:" + key);
            log.info(">>>>>>设置缓存：value:" + inVo.getIsChangeSeats());
            redisTemplate.opsForValue().set(key, inVo.getIsChangeSeats(), 60, TimeUnit.MINUTES);
        }

        return outVo;
    }

    @Override
    public void synJob() throws IOException {
        log.info("小程序>电影模块>出票查询数据接口>定时任务");

        // 获取半小时内所有订单支付成功状态的电影票订单
        LambdaQueryWrapper<BuyerOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BuyerOrder::getOrderType, "DY");
        wrapper.eq(BuyerOrder::getOrderStatus, 2);
        wrapper.ge(BuyerOrder::getCreateTime, LocalDateTime.now().minusMinutes(30));
        List<BuyerOrder> orderList = iBuyerOrderService.getBaseMapper().selectList(wrapper);
        for (BuyerOrder order : orderList) {
            payFlim(order.getOrderId());
            query(order.getOrderId());
        }

    }

    private void setAddPrice(List<MovieSeat> movieSeatList) {
        // 获取电影加价信息
        FlimAddPricePo po = iMoviePlansService.getAddPricePo();

        for (MovieSeat a : movieSeatList) {
            if (a.getPrice() != null) {
                // 计算价格
                BigDecimal price = new BigDecimal(a.getPrice());
                price = price.multiply(BigDecimal.ONE.add(po.getCharge()))
                        .add(po.getAddPrice().multiply(BigDecimal.valueOf(100)))
                        .add(po.getBatchAddPrice().multiply(BigDecimal.valueOf(100)))
                        .setScale(0, BigDecimal.ROUND_HALF_UP);
                a.setSalePrice(price.longValue());
            }
        }
    }


}
